#include<iostream>
#include<stdlib.h>
#include<stdio.h>
#include<string>
#include<algorithm>
#include<assert.h>
#include<vector>

using namespace std;

#define DEFAULT_CAPACITY 3


template <typename T> struct Vector{
	// data
	int _size;
	int _capacity;
	T* _elem;

	//private
	void  copyFrom(const T *a, int lo, int hi){
		_elem = new T[_capacity = 2 * (hi - lo)]; _size = 0;
		while (lo < hi){
			_elem[_size++] = a[lo++];
		}
	}

	T& operator[](int r){
		assert(r < _size && r >= 0);
		return _elem[r];
	}
	Vector<T>& operator=(Vector<T> const & V){
		if (_elem) delete[] _elem;
		copyFrom(V._elem, 0, V._size);
		return *this;
	}




	//test
	void print(string tips = ""){
		cout << tips << endl;
		for (int i = 0; i < _size; i++){
			cout << _elem[i] << " ";
		}
		cout << endl;
	}



	//public
	int size(){
		return _size;
	}
	bool empty() const {
		return !_size;
	}


	Vector(int capacity = DEFAULT_CAPACITY, int size = 0, T initialValue = 0){
		_elem = new T[_capacity = capacity];
		if (initialValue == 0) memset(_elem, 0, sizeof(T)*capacity);
		else for (int i = 0; i < capacity; i++) _elem[i] = initialValue;
		_size = size;
	}
	Vector(T const * V, int lo, int hi){
		copyFrom(V, lo, hi);
	}
	Vector(T const * V, int n){
		copyFrom(V, 0, n);
	}
	Vector(Vector<T> const & V, int lo, int hi){
		copyFrom(V._elem, lo, hi);
	}
	Vector(Vector<T> const & V){
		copyFrom(V._elem, 0, V._size);
	}
	~Vector() {
		delete[] _elem;
	}


};



template <typename T>
void testVector(){
	// assert function
	auto assertVector = [](Vector<T> v, T *a, int n){
		for (int i = 0; i < n; i++){
			assert(v[i] == a[i]);
		};
	};

	//test constructor

	T a[] = { 1, 2, 3, 4, 5 };
	Vector<T> v1(a, 5);
	v1.print("v1");
	assertVector(v1, a, 5);

	Vector<T> v2(a, 2, 4);
	v2.print("v2");
	T b[] = { 3, 4 };
	assertVector(v2, b, 2);

	Vector<T> v3(v1);
	v3.print("v3");
	assertVector(v3, a, 5);

	Vector<T> v4(v1, 2, 4);
	v4.print("v4");
	assertVector(v4, b, 2);

	// test operator[]

	T c[] = { 2, 4, 5, 1, 2 };
	Vector<T> v5(c, 5);
	assert(v5[0] = c[0]);
	assert(v5[4] = c[4]);
	T d[] = { 1, 4, 5, 1, 2 };
	v5[0] = 1;
	v5.print("v5 %1");
	assertVector(v5, d, 5);
	T e[] = { 1, 4, 5, 2, 5 };
	v5[3]++;
	v5[4] = 5;
	v5.print("v5 %2");
	assertVector(v5, e, 5);

	//test opertaor=

	T f[] = { 1, 4, 5, 2, 5 };
	Vector<T> v6(f, 5);
	Vector<T> v7;
	v7 = v6;
	assertVector(v7, f, 5);
	auto v8 = v7;
	assertVector(v8, f, 5);
	v6.print("v6");
	v7.print("v7");
	v8.print("v8");

	//test Vector.size()
	assert(v8.size() == 5);
	Vector<T> v9;
	assert(v9.size() == 0);

	//test Vector.empty()
	assert(v8.empty() == false);
	assert(v9.empty() == true);



	cout << "All test passed.\n\n";
}



int main(){
	testVector<int>();
	testVector<double>();

	vector<int> v;
	v.clear();

	return 0;
}
